package reliability.ui;

import reliability.XmlBuilder;
import reliability.XmlParser;
import reliability.model.GraphModel;
import reliability.model.GraphModelEvent;
import reliability.model.GraphModelListener;

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import java.awt.*;
import java.awt.event.*;
import java.io.File;

public class MainFrame
    extends JFrame
    implements ActionListener, GraphModelListener
{

    private static final String OPEN_FILE = "Открыть";
    private static final String NEW_FILE = "Новый";
    private static final String SAVE_FILE_AS = "Сохранить как";
    private static final String SAVE_FILE = "Сохранить";
    private static final String EXIT = "Выход";
    private static final String ABOUT = "О программе";
    private static final String REFERENCE = "Руководство по использованию";

    GraphPanel graphPanel;
    GraphModel model;
    JMenuBar menuBar;
    JMenuItem openFileMenuItem;
    JMenuItem newFileMenuItem;
    JMenuItem saveFileAsMenuItem;
    JMenuItem saveFileMenuItem;
    JMenuItem exitMenuItem;
    XmlParser xmlParser = new XmlParser();
    XmlBuilder xmlBuilder = new XmlBuilder();
    File selectedFile;
    boolean isFileSaved = true;

    public MainFrame(GraphModel graphModel)
    {
        super();
        model = graphModel;
        model.addListener(this);
        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e)
            {
                closeWindow();
            }
        });

        getContentPane().setLayout(new GridBagLayout());
        setMinimumSize(new Dimension(800, 725));
        setSize(800, 800);
        setTitle("Оценка надежности локальных вычислительных сетей");
        addGraphPanel();
        addInfoPanel();
        initMenuBar();
    }

    public void graphModelChanged(GraphModelEvent graphModelEvent)
    {
        if (graphModelEvent.getId() == GraphModelEvent.GRAPH_UPDATED)
        {
            isFileSaved = false;
        }
    }

    public int showUnsavedStructureWarning()
    {
        Object[] options = {"Да",
                "Нет",
                "Отмена"};
        return JOptionPane.showOptionDialog(this,
                "Сохранить изменения в текущей структуре графа?",
                "Предупреждение",
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.WARNING_MESSAGE,
                null,
                options,
                options[2]);
    }

    public void actionPerformed(ActionEvent actionEvent)
    {
        String actionCommand = actionEvent.getActionCommand();
        if (actionCommand.equals(OPEN_FILE))
        {
            openFile();
        }
        else if (actionCommand.equals(NEW_FILE))
        {
            performNewFile();
        }
        else if (actionCommand.equals(SAVE_FILE_AS))
        {
            performSaveFileAs();
        }
        else if (actionCommand.equals(SAVE_FILE))
        {
            performSaveFile();
        }
        else if (actionCommand.equals(EXIT))
        {
            closeWindow();
        }
        else if (actionCommand.equals(ABOUT))
        {
            showAboutInfo();
        }
        else if (actionCommand.equals(REFERENCE))
        {
            showReference();
        }
    }

    private void showAboutInfo()
    {
        JOptionPane.showMessageDialog(this,
                "Программа расчета надежности локальных вычислительных сетей\n" +
                        "Выполнил: Шадрин Сергей, ПС-32\n" +
                        "Поволжский Государственный Технологический Университет, 2013г.",
                "О программе",
                JOptionPane.INFORMATION_MESSAGE
        );
    }

    private void showReference()
    {
        JOptionPane.showMessageDialog(this,
                "Руководство по использованию:\n" +
                        "Граф сети размещается внутри таблицы в левом верхнем углу.\n" +
                        "Для добавления узла графа сети нажмите левую кнопку мыши над ячейкой таблицы, в которой хотите разместить узел.\n" +
                        "Нельзя добавить узел графа рядом с другим узлом, если он находится в соседней ячейке по горизонтали, вертикали или диагонали.\n" +
                        "Элемент графа можно выбрать нажатием левой кнопки мыши.\n" +
                        "Чтобы добавить связь между узлами графа, выберите узел, из которого будет проводиться связь, затем нажмите правую кнопку мыши над\n" +
                        "узлом сети, в который будет проводиться связь - откроется контекстное меню. Выберите пункт \"Добавить связь\" контекстного меню\n" +
                        "для добавления связи.\n" +
                        "Действия, доступные для конкретного элеметна сети, доступны из контекстного меню при нажатии правой кнопкой мыши над соответствующим\n" +
                        "элементом. (Удаление/добавление узла/связи).\n" +
                        "Возможно добавление резервной линии - дополнительной связи между одними и теми же узлами сети. \n" +
                        "Максимально возможное количество связей между одними и теми же узлами сети - 2.\n" +
                        "При построении графа следует учитывать, что для расчета характеристик сети необходимо, чтобы граф сети был связным.\n" +
                        "При получении нулевого значения вероятности безотказной работы сети методом статистического моделирования следует учитывать, что такой \n" +
                        "результат возможен ввиду особенности метода. В таких случаях возможны два решения - пересчитывать надежность повторно до получения\n" +
                        "ненулевой вероятности, либо увеличить количество испытаний.",
                "Руководство по использованию",
                JOptionPane.INFORMATION_MESSAGE
        );
    }

    private void openFile()
    {
        if (!isFileSaved)
        {
            int chosenOption = showUnsavedStructureWarning();
            if (chosenOption == JOptionPane.YES_OPTION)
            {
                performSaveFile();
                performOpenFile();
            }
            else if (chosenOption == JOptionPane.NO_OPTION)
            {
                performOpenFile();
            }
        }
        else
        {
            performOpenFile();
        }
    }

    private void performNewFile()
    {
        if (!isFileSaved)
        {
            int chosenOption = showUnsavedStructureWarning();
            if (chosenOption == JOptionPane.YES_OPTION)
            {
                performSaveFile();
                model.init();
            }
            else if (chosenOption == JOptionPane.NO_OPTION)
            {
                model.init();
            }
        }
        else
        {
            model.init();
        }
        isFileSaved = true;
    }

    private void closeWindow()
    {
        if (!isFileSaved)
        {
            int chosenOption = showUnsavedStructureWarning();
            if (chosenOption == JOptionPane.YES_OPTION)
            {
                performSaveFile();
                dispose();
            }
            else if (chosenOption == JOptionPane.NO_OPTION)
            {
                dispose();
            }
        }
        else
        {
            dispose();
        }
    }

    private void performOpenFile()
    {
        final GsdFileChooser fileChooser = new GsdFileChooser();
        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
        {
            File selectedFile = fileChooser.getSelectedFile();
            GraphModel model = xmlParser.parse(selectedFile);
            this.model.init(model);
            isFileSaved = true;
        }
    }

    private void performSaveFile()
    {
        if (selectedFile != null)
        {
            xmlBuilder.buildXmlFromModel(model, selectedFile);
            isFileSaved = true;
        }
        else
        {
            performSaveFileAs();
        }
    }

    private void performSaveFileAs()
    {
        final GsdFileChooser fileChooser = new GsdFileChooser();
        if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
        {
            selectedFile = fileChooser.getSelectedFile();
            if (!GsdFileChooser.ACCEPTABLE_EXTENSION.equals(GsdFileChooser.getExtension(selectedFile)))
            {
                selectedFile = new File(selectedFile.getPath() + "." + GsdFileChooser.ACCEPTABLE_EXTENSION);
            }
            xmlBuilder.buildXmlFromModel(model, selectedFile);
            isFileSaved = true;
        }
    }

    private void initMenuBar()
    {
        menuBar = new JMenuBar();

        JMenu fileMenu = new JMenu("Файл");
        newFileMenuItem = new JMenuItem(NEW_FILE);
        newFileMenuItem.addActionListener(this);
        fileMenu.add(newFileMenuItem);

        fileMenu.addSeparator();

        openFileMenuItem = new JMenuItem(OPEN_FILE);
        openFileMenuItem.addActionListener(this);
        fileMenu.add(openFileMenuItem);

        fileMenu.addSeparator();

        saveFileMenuItem = new JMenuItem(SAVE_FILE);
        saveFileMenuItem.addActionListener(this);
        fileMenu.add(saveFileMenuItem);

        saveFileAsMenuItem = new JMenuItem(SAVE_FILE_AS);
        saveFileAsMenuItem.addActionListener(this);
        fileMenu.add(saveFileAsMenuItem);

        fileMenu.addSeparator();

        exitMenuItem = new JMenuItem(EXIT);
        exitMenuItem.addActionListener(this);
        fileMenu.add(exitMenuItem);

        JMenu helpMenu = new JMenu("Помощь");

        JMenuItem aboutMenuItem = new JMenuItem(ABOUT);
        aboutMenuItem.addActionListener(this);
        helpMenu.add(aboutMenuItem);

        JMenuItem referenceMenuItem = new JMenuItem(REFERENCE);
        referenceMenuItem.addActionListener(this);
        helpMenu.add(referenceMenuItem);

        menuBar.add(fileMenu);
        menuBar.add(helpMenu);

        setJMenuBar(menuBar);
    }

    private void addGraphPanel()
    {
        GridBagConstraints graphPanelConstraints = new GridBagConstraints();
        graphPanelConstraints.weightx = 0.8;
        graphPanelConstraints.weighty = 1;
        graphPanelConstraints.gridx = 0;
        graphPanelConstraints.gridy = 0;
        graphPanelConstraints.fill = GridBagConstraints.BOTH;
        graphPanelConstraints.anchor = GridBagConstraints.FIRST_LINE_START;
        graphPanelConstraints.insets = new Insets(7, 7, 7, 0);
        add(getGraphPanel(), graphPanelConstraints);
    }

    private void addInfoPanel()
    {
        InfoPanel infoPanel = new InfoPanel(model);
        infoPanel.setPreferredSize(new Dimension(300, 800));
        infoPanel.setMinimumSize(new Dimension(300, 800));
        GridBagConstraints infoPanelConstraints = new GridBagConstraints();
        infoPanelConstraints.weightx = 0.0;
        infoPanelConstraints.weighty = 1;
        infoPanelConstraints.gridx = 1;
        infoPanelConstraints.gridy = 0;
        add(infoPanel, infoPanelConstraints);
    }

    private GraphPanel getGraphPanel()
    {
        if (graphPanel == null)
        {
            graphPanel = new GraphPanel(model);
            graphPanel.setBackground(new Color(255, 255, 255));
            CompoundBorder compoundBorder = BorderFactory.createCompoundBorder(
                    BorderFactory.createBevelBorder(BevelBorder.RAISED),
                    BorderFactory.createBevelBorder(BevelBorder.LOWERED)
            );
            graphPanel.setBorder(compoundBorder);
        }
        return graphPanel;
    }

}
